#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <DNSServer.h>
#include <EEPROM.h>

char sta_ssid[32] = {0};          //暂存WiFi名
char sta_password[64] = {0};      //暂存WiFi密码
char blinker_key[15] = {"b30b3abc5075"};      //暂存Blinker Key "b30b3abc5075"
const char *AP_NAME = "电脑开机卡AP"; //自定义8266AP热点名
uint8_t blinker_status = 0;
typedef struct
{                  //存储配置结构体
    char sta_ssid[32];          //暂存WiFi名
    char sta_password[32];      //暂存WiFi密码
    char blinker_key[15];             //存Blinker key
} config_type;
config_type config;
#define flashstartaddr 3000
#define flashmax 4096
void saveConfig()
{ //存储配置到"EEPROM"
    Serial.println("save config");
    EEPROM.begin(flashmax);
    // EEPROM.begin(sizeof(config));
    uint8_t *p = (uint8_t *)(&config);
    for (uint i = 0; i < sizeof(config); i++)
    {
        EEPROM.write(flashstartaddr+i, *(p + i));
    }
    EEPROM.commit(); //此操作会消耗flash写入次数
    Serial.printf("EEPROM save,Blinker Key:%s\r\n",config.blinker_key);
    Serial.printf("EEPROM save,sta_ssid:%s\r\n",config.sta_ssid);
    Serial.printf("EEPROM save,sta_password:%s\r\n",config.sta_password);

}

void loadConfig()
{ //从"EEPROM"加载配置
    Serial.println("load config");
    // EEPROM.begin(sizeof(config));
    EEPROM.begin(flashmax);
    uint8_t *p = (uint8_t *)(&config);
    for (uint i = 0; i < sizeof(config); i++)
    {
        *(p + i) = EEPROM.read(flashstartaddr+i);
    }
    
    Serial.printf("EEPROM save,Blinker Key:%s\r\n",config.blinker_key);
    Serial.printf("EEPROM save,sta_ssid:%s\r\n",config.sta_ssid);
    Serial.printf("EEPROM save,sta_password:%s\r\n",config.sta_password);
}

//配网及目标日期设定html页面 监控端配置页面
const char *page_html = "\
<!DOCTYPE html>\r\n\
<html lang='en'>\r\n\
<head>\r\n\
  <meta charset='UTF-8'>\r\n\
  <meta name='viewport' content='width=device-width, initial-scale=1.0'>\r\n\
  <title>Document</title>\r\n\
</head>\r\n\
<body>\r\n\
  <h1>电脑开机卡配置</h1>\r\n\
  <form name='input' action='/' method='POST'>\r\n\
    WiFi名称:\r\n\
    <input type='text' name='ssid'><br>\r\n\
    WiFi密码:\r\n\
    <input type='password' name='password'><br>\r\n\
    Blinker Key:\r\n\
    <input type='Bkey' name='Bkey'><br>\r\n\
    <input type='submit' value='提交'>\r\n\
  </form>\r\n\
</body>\r\n\
</html>\r\n\
";

const byte DNS_PORT = 53;       //DNS端口号默认为53
IPAddress apIP(192, 168, 4, 1); //8266 APIP
DNSServer dnsServer;
ESP8266WebServer server(80);
void connectWiFi();

void handleRoot()
{
    server.send(200, "text/html", page_html);
}
void handleRootPost()
{
    Serial.println("handleRootPost");
    // 接收WIFI SSID字段
    if (server.hasArg("ssid"))
    {
        Serial.print("ssid:");
        strcpy(config.sta_ssid, server.arg("ssid").c_str());
        Serial.println(config.sta_ssid);
    }
    else
    {
        Serial.println("[WebServer]Error, SSID not found!");
        server.send(200, "text/html", "<meta charset='UTF-8'>Error, SSID not found!"); //返回错误页面
        return;
    }
    // 接收WIFI password字段
    if (server.hasArg("password"))
    {
        Serial.print("password:");
        strcpy(config.sta_password, server.arg("password").c_str());
        Serial.println(config.sta_password);
    }
    else
    {
        Serial.println("[WebServer]Error, PASSWORD not found!");
        server.send(200, "text/html", "<meta charset='UTF-8'>Error, PASSWORD not found!");
        return;
    }
    // 接收Blinker 密钥字段
    if (server.hasArg("Bkey"))
    {
        Serial.print("Blinker Key:");
        strcpy(config.blinker_key, server.arg("Bkey").c_str());
        Serial.println(config.blinker_key);
                
    }
    else
    {
        Serial.println("[WebServer]Error, Blinker Key not found!");
        server.send(200, "text/html", "<meta charset='UTF-8'>Error, Blinker Key not found!");
        return;
    }
   
    server.send(200, "text/html", "<meta charset='UTF-8'>提交成功"); //返回保存成功页面
    delay(2000);
    //一切设定完成，连接wifi
    saveConfig();
    connectWiFi();
}


enum{
    Normal,
    ReConnectWifi,
};
uint8_t RunMode = Normal;
void SET_RGB(int R, int G, int B, int bright);
void connectWiFi()
{
    WiFi.mode(WIFI_STA);       //切换为STA模式
    WiFi.setAutoConnect(true); //设置自动连接
    Blinker.begin(config.blinker_key,config.sta_ssid,config.sta_password); //初始化blinker
    // WiFi.begin(config.sta_ssid,config.sta_password);
    Serial.println("");
    Serial.print("Connect WiFi");
    int count = 0;
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(500);

        count++;
        if (count > 20)
        { //10秒过去依然没有自动连上，开启Web配网功能，可视情况调整等待时长
            Serial.println("Timeout! AutoConnect failed");
            WiFi.mode(WIFI_AP); //开热点
            WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
            if (WiFi.softAP(AP_NAME))
            {
                Serial.println("ESP8266 SoftAP is on");
            }
            server.on("/", HTTP_GET, handleRoot);      //设置主页回调函数
            server.onNotFound(handleRoot);             //设置无法响应的http请求的回调函数
            server.on("/", HTTP_POST, handleRootPost); //设置Post请求回调函数
            server.begin();                            //启动WebServer
            Serial.println("WebServer started!");
            if (dnsServer.start(DNS_PORT, "*", apIP))
            { //判断将所有地址映射到esp8266的ip上是否成功
                Serial.println("start dnsserver success.");
            }
            else
                Serial.println("start dnsserver failed.");
            Serial.println("Please reset your WiFi setting.");
            Serial.println("Connect the WiFi named flyAkari, the configuration page will pop up automatically, if not, use your browser to access 192.168.4.1");
            RunMode = ReConnectWifi;
            break; //启动WebServer后便跳出while循环，回到loop
        }
        Serial.print(".");
        if (WiFi.status() == WL_CONNECT_FAILED)
        {
            Serial.print("password:");
            Serial.print(WiFi.psk().c_str());
            Serial.println(" is incorrect");
        }
        if (WiFi.status() == WL_NO_SSID_AVAIL)
        {
            Serial.print("configured SSID:");
            Serial.print(WiFi.SSID().c_str());
            Serial.println(" cannot be reached");
        }
    }
    Serial.println("");
    if (WiFi.status() == WL_CONNECTED)
    {
        Serial.println("WiFi Connected!");
        Serial.print("IP address: ");
        Serial.println(WiFi.localIP());
        server.stop();
        dnsServer.stop();

        if (RunMode == ReConnectWifi)
        {
            RunMode = Normal;
            ESP.restart();
        }
        
        //WiFi连接成功后，热点便不再开启，无法再次通过web配网
        //若WiFi连接断开，ESP8266会自动尝试重新连接，直至连接成功，无需代码干预
        //如需要更换WiFi，请在关闭原WiFi后重启ESP8266，否则上电后会自动连接原WiFi，也就无法进入配网页面
    }
}


// wifi重置
void Resetwifiinfo(void)
{
    WiFi.disconnect();
    while (WiFi.status() == WL_CONNECTED)
    {
        WiFi.disconnect();
        Serial.println("Reset wifi Wait it disconnect!");
        delay(100);
    }

    Serial.println("Reset wifi information");
    WiFi.mode(WIFI_AP); //开热点
    WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
    if (WiFi.softAP(AP_NAME))
    {
        Serial.println("ESP8266 SoftAP is on");
    }
    server.on("/", HTTP_GET, handleRoot);      //设置主页回调函数
    server.onNotFound(handleRoot);             //设置无法响应的http请求的回调函数
    server.on("/", HTTP_POST, handleRootPost); //设置Post请求回调函数
    server.begin();                            //启动WebServer
    Serial.println("WebServer started!");
    if (dnsServer.start(DNS_PORT, "*", apIP))
    { //判断将所有地址映射到esp8266的ip上是否成功
        Serial.println("start dnsserver success.");
    }
    else
        Serial.println("start dnsserver failed.");
    Serial.println("Please reset your WiFi setting.");
    Serial.printf("Connect the WiFi named %s, the configuration page will pop up automatically, if not, use your browser to access 192.168.4.1",config.sta_ssid);
}

